/**
 * @file list.c
 * @author your name (you@domain.com)
 * @brief 
 * @version 0.1
 * @date 2023-08-20
 * 
 * @copyright Copyright (c) 2023
 * 
 */

/******************************* Includes ********************************/
#include "list.h"
#include <string.h>

/******************************* Macros ******************************/


/******************************* Typedef ******************************/



/******************************* Variables ******************************/


/******************************* Functions ******************************/
void list_init(list_node_t *head)
{
     if(head == NULL)
     {
        LIST_E("head is null\n");
        return;
     }
     memset(head, 0, sizeof(list_node_t));
     head->data_len = 0;
     head->next = head;
     head->prev = head;

}

static list_node_t *list_node_create(void *data, int data_len)
{
     if(data == NULL)
     {
        LIST_E("data is null\n");
        return NULL; 
     }

     list_node_t *node = malloc(sizeof(list_node_t));
     if(node == NULL)
     {
        LIST_E("node malloc faill\n");
        goto FAIL;
     }

     memset(node, 0, sizeof(list_node_t));

     node->data = malloc(data_len+1);
     if(node->data == NULL)
     {
        LIST_E("data malloc faill\n");
        goto FAIL;
     }
     
     memset(node->data, 0, data_len+1);
     memcpy(node->data, data, data_len);

     return node;
FAIL:
     if(node != NULL)
     {
        if(node->data != NULL)
        {
            free(node->data);
        }
        free(node);
     }

     return NULL;
}

static void list_node_release(list_node_t *node)
{
     if(node != NULL)
     {
        if(node->data != NULL)
        {
            free(node->data);
        }
        free(node);
     }
}


static inline void __list_add(list_node_t *new, list_node_t *prev, list_node_t *next)
{
	next->prev = new;
	new->next = next;
	new->prev = prev;
	prev->next = new;
}

static void list_add(list_node_t *head, list_node_t *node)
{
    __list_add(node, head, head->next);
}

static void list_add_tail(list_node_t *head, list_node_t *node)
{
    __list_add(node, head->prev, head);
}

int  list_add_node_tail(list_node_t *head, void *data, int data_len)
{
     if(head == NULL)
     {
        LIST_E("head is null\n");
        return -1;
     }
     
     list_node_t *node = list_node_create(data, data_len);
     if(node == NULL)
     {
        LIST_E("node init fail\n");
        return -1;
     }

     list_add_tail(head, node);

     head->data_len++;
  
     return 0;
}

int  list_add_node_head(list_node_t *head, void *data, int data_len)
{
     if(head == NULL)
     {
        LIST_E("head is null\n");
        return -1;
     }
     
     list_node_t *node = list_node_create(data, data_len);
     if(node == NULL)
     {
        LIST_E("node init fail\n");
        return -1;
     }

     list_add(head, node);

     head->data_len++;
     
     return 0;
}

static void list_rm(list_node_t *node)
{
     list_node_t *prev = node->prev;
     list_node_t *next = node->next;
     next->prev = prev;
     prev->next = next;
}

int  list_rm_node(list_node_t *head, list_node_t *node)
{
     if(head == NULL)
     {
        LIST_E("head is null\n");
        return -1;
     }

     if(head == node)
     {
        LIST_E("head is allow rm\n");
        return -1;
     } 

     if(head->data_len <= 0)
     {
        LIST_E("no valid node\n");
        return -1;
     }

     list_rm(node);

     list_node_release(node);

     head->data_len--;

     return 0;
}

int  list_node_count(list_node_t *head)
{
     if(head == NULL)
     {
        LIST_E("head is null\n");
        return -1;
     }

     return head->data_len;
}

void list_node_for_each(list_node_t *head, func_cb cb)
{
     if(head == NULL)
     {
        LIST_E("head is null\n");
        return;
     }

     list_node_t *node = head->next;
     while(node != head)
     {
        list_node_t *temp = node;
        node = node->next;
        if(cb != NULL)
        {
           cb(head, temp);
        }
     }
}

void list_node_for_each_reverse(list_node_t *head, func_cb cb)
{
     if(head == NULL)
     {
        LIST_E("head is null\n");
        return;
     }

     list_node_t *node = head->prev;
     while(node != head)
     {
        list_node_t *temp = node;
        node = node->prev;
        if(cb != NULL)
        {
           cb(head, temp);
        }
     }

}

void list_deinit(list_node_t *head)
{
     if(head == NULL)
     {
        LIST_E("head is null\n");
        return;
     }

     list_node_t *node = head->next;
     while(node != head)
     {    
          list_node_t *temp = node->next;
          list_node_release(node);
          node = temp;
     } 
}

void func_cb_(list_node_t *head,  list_node_t *node)
{
     static int cnt = 0;
     LIST_I("%s\n", (char *)node->data);
     cnt ++;
     if(cnt % 3 == 0)
        list_rm_node(head,node);
}

void func_cb_1(list_node_t *head,  list_node_t *node)
{
     LIST_I("%s\n", (char *)node->data);
     
}

int main(void)
{
    list_node_t head;
    list_init(&head);
    for(int i = 0 ; i < 100; i++)
    {
       char buf[10] = {0};
       snprintf(buf, sizeof(buf), "%d", i);
       list_add_node_head(&head, buf, strlen(buf));
    }

    LIST_I("count: %d\n", list_node_count(&head));

    list_node_for_each(&head, func_cb_);

    LIST_I("count: %d\n", list_node_count(&head));

    list_node_for_each_reverse(&head, func_cb_1);

    list_deinit(&head);

    return 0;
}

/******************************* End of file ******************************/